package com.amkai.aes.webservice.binary.objecthandler.billing;

import java.io.Serializable;
import java.math.BigDecimal;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.amkai.aes.aescommon.exceptions.billing.TransferToBillingGroupExceprion;
import com.amkai.aes.aescommon.service.binary.job.billing.TransferToBgJob;
import com.amkai.aes.aescommon.service.result.billing.TransferToBgJobResult;
import com.amkai.aes.generatedbeans.billingledger.Charge;
import com.amkai.aes.generatedbeans.billingledger.billinggrouptransfer.BillingGroupSetup;
import com.amkai.aes.generatedbeans.billingledger.details.FromToKind;
import com.amkai.aes.generatedbeans.organization.Department;
import com.amkai.aes.webservice.binary.JobObjectHandler;
import com.amkai.common.extensions.hibernate.config.SiteManager;
import com.amkai.common.extensions.hibernate.config.manager.SessionManager;
import com.amkai.rad.designerbase.beans.ChangedKind;

public class TransferToBillingGroupHandler implements JobObjectHandler<TransferToBgJob, Serializable, TransferToBgJobResult> {
	private static final Log logger = LogFactory.getLog(TransferToBillingGroupHandler.class);

	@Override
	public TransferToBgJobResult process(TransferToBgJob job, Serializable object) throws Exception {
		// TODO Auto-generated method stub
		TransferToBgJobResult result = new TransferToBgJobResult();
		try {
			switch (job.getKind()) {
			case GET_SETUP:
				result = getTransferToBgSetup(job);
				break;
			case SAVE_SETUP:
				result = saveTransferToBgSetup(job);
				break;
			case PROCESS_TRANSFER_TO_BILLING_GROUP:
				result = processTransferToBillingGroup(job);
				break;
			}
		} catch (Exception e) {
			result.setException(e);
			logger.error("TransferToBillingGroupHandler", e);
		}
		return result;
	}

	private TransferToBgJobResult processTransferToBillingGroup(TransferToBgJob job) throws Exception {
		TransferToBgJobResult result = new TransferToBgJobResult();
		if (transferValidation(job)) {
			SessionManager sm = SiteManager.Start();
			sm.openTransaction();
			TransferToBillingGroupManager.processTransferToBillingGroup(sm, job);
			sm.commitTransaction();
		}
		return result;
	}

	private boolean transferValidation(TransferToBgJob job) throws Exception {
		boolean result = false;
		String exceptionMessage = null;
		
		SessionManager sm = SiteManager.Start();
		Charge charge = sm.get(Charge.class, job.getChargeId());
		
		BillingGroupSetup bgs = (BillingGroupSetup) sm.execute("FROM BillingGroupSetup WHERE baseOrganization = :dep").setEntity("dep",
				job.getModuleDepartment()).uniqueResult();
		if (charge != null) {

			if (!charge.isIsActive()) {
				exceptionMessage = "Charge is not Active! Transfer between Billing Groups not allowed.";
			} else if (charge.getDue().equals(new BigDecimal(0.00).setScale(2))) {
				exceptionMessage = "Charge Balance must be greater than $0.00 to transfer to a different Billing Group.";
			} else if (!(charge.getFromEntry().getKind().equals(FromToKind.PRIMARY_GUARANTOR) || charge.getFromEntry().getKind().equals(
					FromToKind.PRIMARY_INSURANCE))) {
				exceptionMessage = "Charge has been transferred to a secondary payor/guarantor.  Not eligible to be assigned to a different Billing Group.";
			} else if (charge.getPmCase().getBillingGroups().size() < 2) {
				exceptionMessage = "Only one Billing Group exists for the current Case.  Please add an additional Billing Group to the Case before proceeding.";
			} else if (bgs == null) {
				exceptionMessage = "Configuration Settings incomplete.  Please enter the settings in Configuration > Financial Management > Patient Ledger > Transfer to BG.";
			}
		}
		
		if (exceptionMessage != null) {
			throw new TransferToBillingGroupExceprion(exceptionMessage);
		} else {
			result = true;
		}
		
		return result;
	}

	private TransferToBgJobResult saveTransferToBgSetup(TransferToBgJob job) throws Exception {
		TransferToBgJobResult result = new TransferToBgJobResult();

		SessionManager sm = SiteManager.Start();
		if (!job.getBillingGroupSetup().getChangedKind().equals(ChangedKind.CREATED)) {
			sm.saveRADInTransaction(job.getBillingGroupSetup());
		} else {
			BillingGroupSetup bgs = getTransferToBgSetup(job).getBillingGroupSetup();
			if (bgs == null) {
				job.getBillingGroupSetup().setBaseOrganization(job.getModuleDepartment());
				sm.saveRADInTransaction(job.getBillingGroupSetup());
			} else {
				job.getBillingGroupSetup().setId(bgs.getId());
				job.getBillingGroupSetup().setChangedKind(ChangedKind.CHANGED);
				sm.saveRADInTransaction(job.getBillingGroupSetup());
			}
		}

		return result;
	}

	private TransferToBgJobResult getTransferToBgSetup(TransferToBgJob job) throws Exception {
		// TODO Auto-generated method stub
		TransferToBgJobResult result = new TransferToBgJobResult();
		SessionManager sm = SiteManager.Start();
		
		result.setBillingGroupSetup(getBillingGroupSetup(sm, job.getModuleDepartment()));
		return result;
	}

	public static BillingGroupSetup getBillingGroupSetup(SessionManager sm, Department moduleDepartment) {
		BillingGroupSetup bgs = (BillingGroupSetup) sm.execute("FROM BillingGroupSetup WHERE baseOrganization = :bo").setEntity("bo",
				moduleDepartment).uniqueResult();
		if (bgs != null) {
			bgs.getAllocationCorrectionJournalCode();
			bgs.getAllocationCorrectionJournalCode().getBaseOrganization();
			bgs.getAllocationPostJournalCode();
			bgs.getAllocationPostJournalCode().getBaseOrganization();
			bgs.getBaseOrganization();
			bgs.getDebitCorrectionJournalCode();
			bgs.getDebitCorrectionJournalCode().getBaseOrganization();
			bgs.getDebitPostJournalCode();
			bgs.getDebitPostJournalCode().getBaseOrganization();
			bgs.getChargeCorrectionJournalCode();
			bgs.getChargeCorrectionJournalCode().getBaseOrganization();
			bgs.getPaymentCorrectionJournalCode();
			bgs.getPaymentCorrectionJournalCode().getBaseOrganization();
			bgs.getPaymentPostJournalCode();
			bgs.getPaymentPostJournalCode().getBaseOrganization();
			bgs.getWriteoffCorrectionJournalCode();
			bgs.getWriteoffCorrectionJournalCode().getBaseOrganization();
			bgs.getWriteoffPostJournalCode();
			bgs.getWriteoffPostJournalCode().getBaseOrganization();
		}
		return bgs;
	}

}
